package com.iceberg.adgt.domain;

import com.iceberg.adgt.common.DomainException;
import com.iceberg.adgt.common.Observer;
import com.iceberg.adgt.common.ObserverInterest;
import com.iceberg.adgt.common.ObserverInterestMap;

import java.util.Set;

/**
 * @author David
 */
public final class DomainFacadeImpl implements DomainFacade {

	private static final DomainFacade FACADE = new DomainFacadeImpl();

	private Architecture architecture;
	private Structure structure;
	private ObserverInterestMap oim;

	private DomainFacadeImpl() {
		reset();
	}

	public static DomainFacade getInstance() {
		return FACADE;
	}

	@Override
	public void reset() {
		architecture = new Architecture();
		structure = new Structure(architecture);
		oim = new ObserverInterestMap();
	}

	@Override
	public ArchitectureDTO getArchitecture() {
		return ArchitectureMapper.getArchitectureDTO(architecture);
	}

	@Override
	public void addLayer(String name, int number) throws DomainException {
		architecture.addLayer(name, number);
		oim.notifyObservers(ObserverInterest.LAYERS_CHANGED);
	}

	@Override
	public void addAllowedLayerToLayer(String fromLayer, String toLayer) throws DomainException {
		architecture.addAllowedLayerToLayer(fromLayer, toLayer);
		oim.notifyObservers(ObserverInterest.LAYERS_CHANGED);
	}

	@Override
	public void removeAllowedLayerForLayer(String deleteLayer, String fromLayer) throws DomainException {
		architecture.removeAllowedLayerForLayer(deleteLayer, fromLayer);
		oim.notifyObservers(ObserverInterest.LAYERS_CHANGED);
	}

	@Override
	public void removeLayer(String name) {
		architecture.removeLayer(name);
		oim.notifyObservers(ObserverInterest.LAYERS_CHANGED);
		oim.notifyObservers(ObserverInterest.UNITS_CHANGED);
	}

	@Override
	public void addUnitToLayer(String unitName, String type, String layerName) throws DomainException {
		architecture.addUnitToLayer(unitName, type, layerName);
		oim.notifyObservers(ObserverInterest.UNITS_CHANGED);
	}

	@Override
	public void removeUnitFromLayer(String unitName, String unitType, String layerName) {
		architecture.removeUnitFromLayer(unitName, unitType, layerName);
		oim.notifyObservers(ObserverInterest.UNITS_CHANGED);
	}

	@Override
	public void setArchitectureAuthor(String name) throws DomainException {
		architecture.setAuthor(name);
		oim.notifyObservers(ObserverInterest.ARCHITECTURE_CHANGED);
	}

	@Override
	public void setArchitectureName(String name) throws DomainException {
		architecture.setName(name);
		oim.notifyObservers(ObserverInterest.ARCHITECTURE_CHANGED);
	}

	@Override
	public void setStructureAuthor(String name) throws DomainException {
		structure.setAuthor(name);
		oim.notifyObservers(ObserverInterest.STRUCTURE_CHANGED);
	}

	@Override
	public void setStructureName(String name) throws DomainException {
		structure.setName(name);
		oim.notifyObservers(ObserverInterest.STRUCTURE_CHANGED);
	}

	@Override
	public void addObserver(Observer observer, ObserverInterest interest) {
		this.oim.put(interest, observer);
	}

	@Override
	public Set<UnitTypeDTO> getUnitTypes() {
		return UnitTypeMapper.getUnitTypeDTOList();
	}

	@Override
	public StructureDTO getStructure() {
		return StructureMapper.getStructureDTO(structure);
	}
}
